home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / BOUNDARY.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  7.6 KB  |  350 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1997.  */
  3.  
  4. /* This program is freely distributable without licensing fees  and is
  5.    provided without guarantee or warrantee expressed or  implied. This
  6.    program is -not- in the public domain. */
  7.  
  8. /* This example shows how to use the GLU polygon tessellator to determine the 
  9.  
  10.    2D boundary of OpenGL rendered objects.  The program uses OpenGL's
  11.    feedback mechanim to capture transformed polygons and then feeds them to
  12.    the GLU tesselator in GLU_TESS_WINDING_NONZERO and GLU_TESS_BOUNDARY_ONLY
  13.    mode. */
  14.  
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <GL/glut.h>
  19.  
  20. #ifdef GLU_VERSION_1_2
  21.  
  22. #ifndef CALLBACK
  23. #define CALLBACK
  24. #endif
  25.  
  26. enum {
  27.   M_TORUS, M_CUBE, M_SPHERE, M_ICO, M_TEAPOT, M_ANGLE, M_BOUNDARY
  28. };
  29.  
  30. struct VertexHolder {
  31.   struct VertexHolder *next;
  32.   GLfloat v[2];
  33. };
  34.  
  35. int shape = M_TORUS;
  36. int boundary = 1;
  37. GLfloat angle = 0.0;
  38.  
  39. GLfloat lightDiffuse[] =
  40. {1.0, 0.0, 0.0, 1.0};
  41. GLfloat lightPosition[] =
  42. {1.0, 1.0, 1.0, 0.0};
  43.  
  44. GLUtesselator *tess;
  45. int width, height;
  46.  
  47. static void CALLBACK
  48. begin(GLenum type)
  49. {
  50.   assert(type == GL_LINE_LOOP);
  51.   glBegin(type);
  52. }
  53.  
  54. static void CALLBACK
  55. vertex(void *data)
  56. {
  57.   GLfloat *v = data;
  58.   glVertex2fv(v);
  59. }
  60.  
  61. static void CALLBACK
  62. end(void)
  63. {
  64.   glEnd();
  65. }
  66.  
  67. static GLfloat *combineList = NULL;
  68. static int combineListSize = 0;
  69. static int combineNext = 0;
  70. static struct VertexHolder *excessList = NULL;
  71.  
  72. static void
  73. freeExcessList(void)
  74. {
  75.   struct VertexHolder *holder, *next;
  76.  
  77.   holder = excessList;
  78.   while (holder) {
  79.     next = holder->next;
  80.     free(holder);
  81.     holder = next;
  82.   }
  83.   excessList = NULL;
  84. }
  85.  
  86. /* ARGSUSED1 */
  87. static void CALLBACK
  88. combine(GLdouble coords[3], void *d[4], GLfloat w[4], void **dataOut)
  89. {
  90.   GLfloat *newCoords;
  91.   struct VertexHolder *holder;
  92.  
  93.   /* XXX Careful, some systems still don't understand realloc of NULL. */
  94.   if (combineNext >= combineListSize) {
  95.     holder = (struct VertexHolder *) malloc(sizeof(struct VertexHolder));
  96.     holder->next = excessList;
  97.     excessList = holder;
  98.     newCoords = holder->v;
  99.   } else {
  100.     newCoords = &combineList[combineNext * 2];
  101.   }
  102.  
  103.   newCoords[0] = coords[0];
  104.   newCoords[1] = coords[1];
  105.   *dataOut = newCoords;
  106.  
  107.   combineNext++;
  108. }
  109.  
  110. static void CALLBACK
  111. error(GLenum errno)
  112. {
  113.   printf("ERROR: %s\n", gluErrorString(errno));
  114. }
  115.  
  116. void
  117. reshape(int w, int h)
  118. {
  119.   width = w;
  120.   height = h;
  121.   glViewport(0, 0, width, height);
  122. }
  123.  
  124. void
  125. processFeedback(GLint size, GLfloat * buffer)
  126. {
  127.   GLfloat *loc, *end;
  128.   GLdouble v[3];
  129.   int token, nvertices, i;
  130.  
  131.   if (combineNext > combineListSize) {
  132.     freeExcessList();
  133.     combineListSize = combineNext;
  134.     combineList = realloc(combineList, sizeof(GLfloat) * 2 * combineListSize);
  135.   }
  136.   combineNext = 0;
  137.  
  138.   gluTessBeginPolygon(tess, NULL);
  139.   loc = buffer;
  140.   end = buffer + size;
  141.   while (loc < end) {
  142.     token = *loc;
  143.     loc++;
  144.     switch (token) {
  145.     case GL_POLYGON_TOKEN:
  146.       nvertices = *loc;
  147.       loc++;
  148.       assert(nvertices >= 3);
  149.       gluTessBeginContour(tess);
  150.       for (i = 0; i < nvertices; i++) {
  151.         v[0] = loc[0];
  152.         v[1] = loc[1];
  153.         v[2] = 0.0;
  154.         gluTessVertex(tess, v, loc);
  155.         loc += 2;
  156.       }
  157.       gluTessEndContour(tess);
  158.       break;
  159.     default:
  160.       /* Ignore everything but polygons. */
  161.       ;
  162.     }
  163.   }
  164.   gluTessEndPolygon(tess);
  165. }
  166.  
  167. int
  168. determineBoundary(void (*renderFunc) (void), int probableSize)
  169. {
  170.   static GLfloat *feedbackBuffer = NULL;
  171.   static int bufferSize = 0;
  172.   GLint returned;
  173.  
  174.   if (bufferSize > probableSize) {
  175.     probableSize = bufferSize;
  176.   }
  177. doFeedback:
  178.  
  179.   /* XXX Careful, some systems still don't understand realloc of NULL. */
  180.   if (bufferSize < probableSize) {
  181.     bufferSize = probableSize;
  182.     feedbackBuffer = realloc(feedbackBuffer, bufferSize * sizeof(GLfloat));
  183.   }
  184.   glFeedbackBuffer(bufferSize, GL_2D, feedbackBuffer);
  185.  
  186.   (void) glRenderMode(GL_FEEDBACK);
  187.  
  188.   (*renderFunc) ();
  189.  
  190.   returned = glRenderMode(GL_RENDER);
  191. #if 0
  192.   if (returned == -1) {
  193. #else
  194.   /* XXX RealityEngine workaround. */
  195.   if (returned == -1 || returned == probableSize) { 
  196. #endif
  197.     probableSize = probableSize + (probableSize >> 1);
  198.     goto doFeedback;    /* Try again with larger feedback buffer. */
  199.   }
  200.   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  201.   glMatrixMode(GL_PROJECTION);
  202.   glLoadIdentity();
  203.   gluOrtho2D(0, width, 0, height);
  204.   glMatrixMode(GL_MODELVIEW);
  205.   glLoadIdentity();
  206.   processFeedback(returned, feedbackBuffer);
  207.   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  208.  
  209.   return returned;
  210. }
  211.  
  212. void
  213. render(void)
  214. {
  215.   glMatrixMode(GL_PROJECTION);
  216.   glLoadIdentity();
  217.   gluPerspective( /* field of view in degree */ 30.0,
  218.   /* aspect ratio */ 1.0,
  219.     /* Z near */ 1.0, /* Z far */ 20.0);
  220.   glMatrixMode(GL_MODELVIEW);
  221.   glLoadIdentity();
  222.   gluLookAt(0.0, 0.0, 10.0,  /* eye is at (0,0,5) */
  223.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  224.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  225.  
  226.   glPushMatrix();
  227.   glRotatef(angle, 1.0, 0.3, 0.0);
  228.   switch (shape) {
  229.   case M_TORUS:
  230.     glutSolidTorus(0.275, 0.85, 8, 8);
  231.     break;
  232.   case M_CUBE:
  233.     glutSolidCube(1.0);
  234.     break;
  235.   case M_SPHERE:
  236.     glutSolidSphere(1.0, 10, 10);
  237.     break;
  238.   case M_ICO:
  239.     glutSolidIcosahedron();
  240.     break;
  241.   case M_TEAPOT:
  242.     glutSolidTeapot(1.0);
  243.     break;
  244.   }
  245.   glPopMatrix();
  246. }
  247.  
  248. void
  249. display(void)
  250. {
  251.   if (boundary) {
  252.     glClear(GL_COLOR_BUFFER_BIT);
  253.     glDisable(GL_LIGHTING);
  254.     glDisable(GL_DEPTH_TEST);
  255.     glEnable(GL_CULL_FACE);
  256.     determineBoundary(render, 250);
  257.   } else {
  258.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  259.     glEnable(GL_LIGHTING);
  260.     glEnable(GL_DEPTH_TEST);
  261.     glDisable(GL_CULL_FACE);
  262.     render();
  263.   }
  264.   glutSwapBuffers();
  265. }
  266.  
  267. void
  268. menu(int value)
  269. {
  270.   switch (value) {
  271.   case M_TORUS:
  272.   case M_CUBE:
  273.   case M_SPHERE:
  274.   case M_ICO:
  275.   case M_TEAPOT:
  276.     shape = value;
  277.     break;
  278.   case M_ANGLE:
  279.     angle += 10.0;
  280.     break;
  281.   case M_BOUNDARY:
  282.     boundary = !boundary;  /* Toggle. */
  283.     break;
  284.   }
  285.   glutPostRedisplay();
  286. }
  287.  
  288. /* ARGSUSED1 */
  289. void
  290. special(int key, int x, int y)
  291. {
  292.   switch (key) {
  293.   case GLUT_KEY_UP:
  294.     angle += 10.0;
  295.     glutPostRedisplay();
  296.     break;
  297.   case GLUT_KEY_DOWN:
  298.     angle -= 10.0;
  299.     glutPostRedisplay();
  300.     break;
  301.   }
  302. }
  303.  
  304. int
  305. main(int argc, char **argv)
  306. {
  307.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
  308.   glutInit(&argc, argv);
  309.  
  310.   glutCreateWindow("boundary");
  311.   glutDisplayFunc(display);
  312.   glutReshapeFunc(reshape);
  313.   glutSpecialFunc(special);
  314.  
  315.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
  316.   glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
  317.   glEnable(GL_LIGHT0);
  318.  
  319.   tess = gluNewTess();
  320.   gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE);
  321.   gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  322.   gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)())begin);
  323.   gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)())vertex);
  324.   gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)())end);
  325.   gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK*)())error);
  326.   gluTessCallback(tess, GLU_TESS_COMBINE, (void (CALLBACK*)())combine);
  327.  
  328.   glutCreateMenu(menu);
  329.   glutAddMenuEntry("Torus", M_TORUS);
  330.   glutAddMenuEntry("Cube", M_CUBE);
  331.   glutAddMenuEntry("Sphere", M_SPHERE);
  332.   glutAddMenuEntry("Icosahedron", M_ICO);
  333.   glutAddMenuEntry("Teapot", M_TEAPOT);
  334.   glutAddMenuEntry("Angle", M_ANGLE);
  335.   glutAddMenuEntry("Toggle boundary", M_BOUNDARY);
  336.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  337.  
  338.   glutMainLoop();
  339.   return 0;             /* ANSI C requires main to return int. */
  340. }
  341.  
  342. #else
  343. int main(int argc, char** argv)
  344. {
  345.   fprintf(stderr, "This program demonstrates the new tesselator API in GLU 1.2.\n");
  346.   fprintf(stderr, "Your GLU library does not support this new interface, sorry.\n");
  347.   return 0;
  348. }
  349. #endif  /* GLU_VERSION_1_2 */
  350.